﻿using System;
using System.Windows.Input;
using Plugins.Base;
using Utils.Wpf;

namespace TimeBarPlugin
{
	internal class InternalStateVM : ViewModelValidatedBase, IDisposable
	{
		#region Attributes

		private readonly DecisionEngineData _decisionEngineData;
		private readonly DecisionEngineDataSource _dataSource;

		#endregion

		#region Properties

		public EngineState State
		{
			get
			{
				return _decisionEngineData.State;
			}
			set
			{
				if (_decisionEngineData.State != value)
				{
					_decisionEngineData.State = value;
					base.OnPropertyChanged("State");
				}
			}
		}

		public EngineState PreviousState
		{
			get
			{
				return _decisionEngineData.PreviousState;
			}
			set
			{
				if (_decisionEngineData.PreviousState != value)
				{
					_decisionEngineData.PreviousState = value;
					base.OnPropertyChanged("PreviousState");
				}
			}
		}

		public decimal StartValue
		{
			get
			{
				return _decisionEngineData.StartValue;
			}
			set
			{
				if (_decisionEngineData.StartValue != value)
				{
					_decisionEngineData.StartValue = value;
					base.OnPropertyChanged("StartValue");
				}
			}
		}

		public decimal HighThreshold
		{
			get
			{
				return _decisionEngineData.HighThreshold;
			}
			set
			{
				if (_decisionEngineData.HighThreshold != value)
				{
					_decisionEngineData.HighThreshold = value;
					base.OnPropertyChanged("HighThreshold");
				}
			}
		}

		public decimal LowThreshold
		{
			get
			{
				return _decisionEngineData.LowThreshold;
			}
			set
			{
				if (_decisionEngineData.LowThreshold != value)
				{
					_decisionEngineData.LowThreshold = value;
					base.OnPropertyChanged("LowThreshold");
				}
			}
		}

		public decimal StopLoss
		{
			get
			{
				return _decisionEngineData.StopLoss;
			}
			set
			{
				if (_decisionEngineData.StopLoss != value)
				{
					_decisionEngineData.StopLoss = value;
					base.OnPropertyChanged("StopLoss");
				}
			}
		}

		public int CurrentVolume
		{
			get
			{
				return _decisionEngineData.CurrentVolume;
			}
			set
			{
				if (_decisionEngineData.CurrentVolume != value)
				{
					_decisionEngineData.CurrentVolume = value;
					base.OnPropertyChanged("CurrentVolume");
				}
			}
		}

		public decimal BidValue
		{
			get
			{
				return _decisionEngineData.LastQuotation != null ? _decisionEngineData.LastQuotation.Buyers[0].Value : 0;
			}
		}

		public decimal AskValue
		{
			get
			{
				return _decisionEngineData.LastQuotation != null ? _decisionEngineData.LastQuotation.Sellers[0].Value : 0;
			}
		}

		public TimeSpan LastData
		{
			get
			{
				return _decisionEngineData.LastQuotation != null ? _decisionEngineData.LastQuotation.Date.TimeOfDay : TimeSpan.Zero;
			}
		}

		public DateTime ProcessedDay
		{
			get
			{
				return _decisionEngineData.ProcessedDay;
			}
			set
			{
				if (_decisionEngineData.ProcessedDay != value)
				{
					_decisionEngineData.ProcessedDay = value;
					base.OnPropertyChanged("ProcessedDay");
				}
			}
		}

		public ICommand LoadStateCommand { get; private set; }
		public ICommand SaveStateCommand { get; private set; }
		public ICommand ResetStateCommand { get; private set; }

		#endregion

		#region Public Methods

		public InternalStateVM(DecisionEngineData decisionEngineData, DecisionEngineDataSource dataSource)
		{
			_decisionEngineData = decisionEngineData;
			_dataSource = dataSource;
			_decisionEngineData.PropertyChanged += DecisionEngineData_PropertyChanged; // Disposed

			this.LoadStateCommand = new DelegateCommand(ExecuteLoadState, CanLoadState);
			this.SaveStateCommand = new DelegateCommand(ExecuteSaveState);
			this.ResetStateCommand = new DelegateCommand(ExecuteResetState);
		}

		protected override string ValidateField(string fieldName)
		{
			string result = null;

			if (fieldName == "CurrentVolume")
			{
				if (this.CurrentVolume < 0)
				{
					base.ValidatedErrors[fieldName] = true;
					result = "The current volume cannot be less than 0";
				}
			}
			else if (fieldName == "HighThreshold")
			{
				if (this.HighThreshold < 0)
				{
					base.ValidatedErrors[fieldName] = true;
					result = "The high threshold cannot be less than 0";
				}
			}
			else if (fieldName == "LowThreshold")
			{
				if (this.LowThreshold < 0)
				{
					base.ValidatedErrors[fieldName] = true;
					result = "The low threshold cannot be less than 0";
				}
			}
			else if (fieldName == "StartValue")
			{
				if (this.StartValue < 0)
				{
					base.ValidatedErrors[fieldName] = true;
					result = "The start value cannot be less than 0";
				}
			}
			else if (fieldName == "StopLoss")
			{
				if (this.StopLoss < 0)
				{
					base.ValidatedErrors[fieldName] = true;
					result = "The stop loss cannot be less than 0";
				}
			}

			return result;
		}

		#endregion

		#region Event Handlers

		private void DecisionEngineData_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
		{
			if (e.PropertyName == "LastQuotation")
			{
				base.OnPropertyChanged("BidValue");				
				base.OnPropertyChanged("AskValue");
				base.OnPropertyChanged("LastData");
			}
			else
			{
				base.OnPropertyChanged(e.PropertyName);	
			}
		}
		
		#endregion

		#region Private Methods

		private void ExecuteLoadState()
		{
			_decisionEngineData.Copy(_dataSource.Load());
		}

		private bool CanLoadState()
		{
			return _dataSource.IsDataToLoad();
		}

		private void ExecuteSaveState()
		{
			_dataSource.Save(_decisionEngineData);
		}

		private void ExecuteResetState()
		{
			_decisionEngineData.Copy(new DecisionEngineData());
		}

		#endregion

		#region IDisposable

		protected bool Disposed { get; private set; }

		private void Dispose(bool disposing)
		{
			if (!this.Disposed)
			{
				this.InternalDispose(disposing);
			}

			this.Disposed = true;
		}

		protected virtual void InternalDispose(bool disposing)
		{
			if (disposing)
			{
				_decisionEngineData.PropertyChanged -= DecisionEngineData_PropertyChanged;
			}

			// Dispose here only unmanaged objects 
			// Don’t use managed objects here because maybe 
			// they have been finalized already
		}

		public void Dispose()
		{
			this.Dispose(true);
			GC.SuppressFinalize(this);
		}

		~InternalStateVM()
		{
			this.Dispose(false);
		}

		#endregion
	}
}
